package nio.example.study.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.flush.FlushConsolidationHandler;
import io.netty.handler.ipfilter.IpFilterRuleType;
import io.netty.handler.ipfilter.IpSubnetFilterRule;
import io.netty.handler.ipfilter.RuleBasedIpFilter;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.UnorderedThreadPoolEventExecutor;
import nio.example.study.server.codec.OrderFrameDecoder;
import nio.example.study.server.codec.OrderFrameEncoder;
import nio.example.study.server.codec.OrderProtocolDecoder;
import nio.example.study.server.codec.OrderProtocolEncoder;
import nio.example.study.server.handler.AuthHandler;
import nio.example.study.server.handler.MetricHandler;
import nio.example.study.server.handler.OrderServerProcessHandler;
import nio.example.study.server.handler.ServerIdleCheckHandler;

import javax.net.ssl.SSLException;
import java.security.cert.CertificateException;
import java.util.concurrent.ExecutionException;

public class Server {

	public static void main(String[] args) throws InterruptedException, ExecutionException, CertificateException, SSLException {
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		serverBootstrap.channel(NioServerSocketChannel.class);
		serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
		NioEventLoopGroup boss = new NioEventLoopGroup(0, new DefaultThreadFactory("boss"));
		NioEventLoopGroup worker = new NioEventLoopGroup(0, new DefaultThreadFactory("worker"));
		serverBootstrap.group(boss, worker);

		MetricHandler metricHandler = new MetricHandler();
		UnorderedThreadPoolEventExecutor eventExecutors = new UnorderedThreadPoolEventExecutor(10, new DefaultThreadFactory("bussiness"));
		// NioEventLoopGroup bussiness = new NioEventLoopGroup(0, new DefaultThreadFactory("bussiness"));
		GlobalTrafficShapingHandler globalTrafficShapingHandler = new GlobalTrafficShapingHandler(new NioEventLoopGroup(), 100 * 1024 * 1024,
				100 * 1024 * 1024);

		IpSubnetFilterRule ipSubnetFilterRule = new IpSubnetFilterRule("127.1.0.1", 16, IpFilterRuleType.REJECT);

		AuthHandler authHandler = new AuthHandler();

		// ssl支持
		//SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate();
		//System.out.println(selfSignedCertificate.certificate());
		//SslContext sslContext = SslContextBuilder.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()).build();

		serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
			@Override
			protected void initChannel(NioSocketChannel ch) throws Exception {
				ChannelPipeline pipeline = ch.pipeline();
				pipeline.addLast("LoggingHandler", new LoggingHandler(LogLevel.DEBUG));


				pipeline.addLast("ipFilter", new RuleBasedIpFilter(ipSubnetFilterRule));
				// 流量整形
				pipeline.addLast("TsHandler", globalTrafficShapingHandler);

				pipeline.addLast("idleCheck", new ServerIdleCheckHandler());

				//SslHandler sslHandler = sslContext.newHandler(ch.alloc());
				//pipeline.addLast("sslHandler", sslHandler);

				pipeline.addLast("frameDecoder", new OrderFrameDecoder());
				pipeline.addLast("FrameEncoder", new OrderFrameEncoder());
				pipeline.addLast("ProtocolEncoder", new OrderProtocolEncoder());
				pipeline.addLast("ProtocolDecoder", new OrderProtocolDecoder());
				pipeline.addLast("MetricHandler", metricHandler);

				pipeline.addLast("authHandler", authHandler);

				pipeline.addLast(new LoggingHandler(LogLevel.INFO));

				pipeline.addLast("flushEnhance", new FlushConsolidationHandler(5, true));
				pipeline.addLast(eventExecutors, new OrderServerProcessHandler());
			}
		});
		ChannelFuture channelFuture = serverBootstrap.bind(8090).sync();
		channelFuture.channel().closeFuture().get();
	}
}
